Skip to content

Conversation

@lucasromanomr
Copy link
Contributor

Added support for enable code coverage for all targets.

For auto scheme generation default valou ir False

xcodeproj(
        …
        scheme_autogeneration_config = xcschemes.autogeneration_config(
             test = xcschemes.autogeneration.test(
                 test_options = xcschemes.test_options(
                     app_language = "en",
                     app_region = "US",
                     code_coverage = False,
                 )
             )
        ),
        …
)

For configure in scheme:

xcschemes.scheme(
        …
        test = xcschemes.test(
            …
            test_options = xcschemes.test_options(
                app_language = "en",
                app_region = "US",
                code_coverage = True,
            ),
            …
        ),
        …
)
image

@lucasromanomr lucasromanomr requested a review from a team as a code owner November 19, 2024 18:25
@lucasromanomr lucasromanomr force-pushed the feat/add-coverage-options branch 4 times, most recently from 205a377 to f0b4bdf Compare November 19, 2024 18:44
Copy link
Contributor

@brentleyjones brentleyjones left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you rebase?

@erneestoc
Copy link

curious, was there a change that would make coverage work now? this is just for the schema and we'd still need something like this #1119 (comment) correct?

@brentleyjones
Copy link
Contributor

AFAIK coverage in Xcode is still broken.

@lucasromanomr
Copy link
Contributor Author

Can you rebase?

Yes, I will check everything I have here to do a rebase, and modify something if necessary.

curious, was there a change that would make coverage work now? this is just for the schema and we'd still need something like this #1119 (comment) correct?

The coverage is still broken, what is done here is just to set it as an option to enable, here we use internal adjustments to achieve coverage.

@lucasromanomr lucasromanomr force-pushed the feat/add-coverage-options branch from b76b73f to d493a75 Compare April 23, 2025 16:45
@lucasromanomr lucasromanomr force-pushed the feat/add-coverage-options branch 2 times, most recently from 69fa079 to 0900ce5 Compare November 4, 2025 15:22
@lucasromanomr
Copy link
Contributor Author

@brentleyjones After a while I went back to implement it, I did a rebase to incorporate the latest changes, and I also tested it in the project, and everything worked :)

One point to note is that Xcode coverage is still not working. This is just an option to enable it. Internally, we use a workaround to have coverage, which is why we implemented this option to enable it by default.

@brentleyjones
Copy link
Contributor

What’s the workaround?

@lucasromanomr
Copy link
Contributor Author

lucasromanomr commented Nov 4, 2025

What’s the workaround?

It would be following the same approach as here: #1119 (comment)

However, implemented differently.

In this case, internally at PicPay, we looked at the path of two apps and then at where several modules are located.

Specific configurations were added to the module target, and the apps were separated (in this case, we have two apps).

diff --git a/tools/worker/swift_runner.cc b/tools/worker/swift_runner.cc
index 6610e589e..e0807a4ee 100644
--- a/tools/worker/swift_runner.cc
+++ b/tools/worker/swift_runner.cc
@@ -302,6 +302,25 @@ bool SwiftRunner::ProcessArgument(
     }
 #endif
   };
+  
+  auto add_prefix_map_flags_for_custom_coverage = [&](const std::string& flag, const std::string& modules_dir_name) {
+    // cwd real (execution root)
+    const auto cwd = std::filesystem::current_path();
+
+    // Calcula target_path = canonical(cwd / modules_dir_name).parent_path();
+    const auto target_path = std::filesystem::canonical(cwd / modules_dir_name).parent_path();
+
+    consumer(flag);
+    consumer(std::filesystem::current_path().string() + "=" + target_path.string());
+
+#if __APPLE__
+    std::string developer_dir = "__BAZEL_XCODE_DEVELOPER_DIR__";
+    if (bazel_placeholder_substitutions_.Apply(developer_dir)) {
+        consumer(flag);
+        consumer(developer_dir + "=/PLACEHOLDER_DEVELOPER_DIR");
+    }
+#endif
+  };
 
   if (arg[0] == '@') {
     changed = ProcessPossibleResponseFile(arg, consumer);
@@ -313,6 +332,15 @@ bool SwiftRunner::ProcessArgument(
         // without breaking hermiticity.
         add_prefix_map_flags("-debug-prefix-map");
         changed = true;
+      } else if (new_arg == "-app-coverage-hack") {
+        add_prefix_map_flags_for_custom_coverage("-coverage-prefix-map", "Modules");
+        changed = true;
+      } else if (new_arg == "-app-coverage-hack-app-app1") {
+        add_prefix_map_flags_for_custom_coverage("-coverage-prefix-map", "App1");
+        changed = true;
+      } else if (new_arg == "-app-coverage-hack-app-app2") {
+        add_prefix_map_flags_for_custom_coverage("-coverage-prefix-map", "App2");
+        changed = true;
       } else if (new_arg == "-coverage-prefix-pwd-is-dot") {
         // Replace the $PWD with . to make the paths relative to the workspace
         // without breaking hermiticity.

in swift_library of app:

swift_library(
    name = "App1.library",
    srcs = [":App1SourceCode"],
    copts = select({
        "//Bazel_rules:scheme_prod": [],
        "//Bazel_rules:coverage_in_xcode": [
            "-Xwrapped-swift=-app-coverage-hack-app-1",
            "-D",
            "DEBUG",
        ],
        "//conditions:default": [
            "-D",
            "DEBUG",
        ],
    }),
    features = select({
        "//Bazel_rules:coverage_in_xcode": [
            "-swift.coverage_prefix_map",
            "-swift.file_prefix_map",
            "swift.coverage",
        ],
        "//conditions:default": [],
    }),
    linkopts = select({
        "//Bazel_rules:coverage_in_xcode": [
            "-fprofile-instr-generate",
        ],
        "//conditions:default": [],
    }),
    module_name = "App1",
    tags = ["manual"],
    visibility = ["//visibility:public"],
    deps = [...]
    alwayslink = True,
)

And in xcodeproj.bazelrc has a config:

build:rules_xcodeproj --//:enable_coverage_in_xcode=coverage

in BUILD.bazel

string_flag(
    name = "enable_coverage_in_xcode",
    build_setting_default = "no_coverage",
    visibility = ["//visibility:public"],
)

config_setting(
    name = "coverage_in_xcode",
    flag_values = {
        ":enable_coverage_in_xcode": "coverage",
    },
    visibility = ["//visibility:public"],
)

@lucasromanomr lucasromanomr force-pushed the feat/add-coverage-options branch from 0900ce5 to 873875e Compare November 7, 2025 13:00
Signed-off-by: Lucas Romano <[email protected]>

update autogeneration_config docs

Signed-off-by: Lucas Romano <[email protected]>

Update tools/generators/xcschemes/test/CreateAutomaticSchemeInfoTests.swift

Co-authored-by: Brentley Jones <[email protected]>
Signed-off-by: Lucas Romano <[email protected]>

Update tools/generators/xcschemes/test/CreateAutomaticSchemeInfoTests.swift

Co-authored-by: Brentley Jones <[email protected]>
Signed-off-by: Lucas Romano <[email protected]>

Update tools/generators/xcschemes/src/Generator/Generator.swift

Signed-off-by: Lucas Romano <[email protected]>
@lucasromanomr lucasromanomr force-pushed the feat/add-coverage-options branch from 873875e to 93d6116 Compare November 12, 2025 13:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants